package excelrept

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/xuri/excelize/v2"
)

//MergeCell 合并单元格信息
type MergeCell struct {
	Range   string `json:"range"`
	Colspan int    `json:"colspan"`
	Rowspan int    `json:"rowspan"`
	Value   string `json:"value"`
}

//XlsxHelper Xlsx读写器
type XlsxHelper struct {
	file        *excelize.File
	sheetMCells map[string]map[string]MergeCell
}

//NewXlsxHelper 新建XlsxHelper
func NewXlsxHelper(path string) (xlsx *XlsxHelper, err error) {
	xlsx = &XlsxHelper{sheetMCells: make(map[string]map[string]MergeCell, 3)}
	xlsx.file, err = excelize.OpenFile(path)
	return
}

//NewXlsxHelper2 新建XlsxHelper2
func NewXlsxHelper2(file *excelize.File) (xlsx *XlsxHelper) {
	xlsx = &XlsxHelper{sheetMCells: make(map[string]map[string]MergeCell, 3)}
	xlsx.file = file
	return
}

//ReaderCells 从指定的sheet和范围中读取数据
func (x *XlsxHelper) ReaderCells(sheet string, rg string) (cells map[string]string, rowHs map[int]float64, err error) {
	if rg == "" {
		return
	}
	aa := strings.Split(rg, ":")
	if len(aa) != 2 {
		err = fmt.Errorf("非法的单元格范围表达式%s", rg)
		return
	}
	var scol, srow, ecol, erow int
	scol, srow, err = parseAxis(aa[0])
	if err != nil {
		return
	}
	ecol, erow, err = parseAxis(aa[1])
	if err != nil {
		return
	}
	if scol > ecol {
		err = fmt.Errorf("非法的单元格范围表达式%s", rg)
		return
	}
	if srow > erow {
		err = fmt.Errorf("非法的单元格表达式%s", rg)
		return
	}
	var axis string
	cells = make(map[string]string)
	rowHs = make(map[int]float64)
	var val string
	var colName string
	for j := srow; j <= erow; j++ {
		rowHs[j], err = x.file.GetRowHeight(sheet, j)
		if err != nil {
			return
		}
		for i := scol; i <= ecol; i++ {
			colName, err = excelize.ColumnNumberToName(i)
			if err != nil {
				return
			}
			axis = colName + strconv.Itoa(j)
			// if x.isMerge(sheet, axis) {
			// 	continue
			// }
			val, err = x.file.GetCellValue(sheet, axis)
			if err != nil {
				return
			}
			cells[axis] = val
		}
	}
	return
}

func (x *XlsxHelper) isMerge(sheet string, cell string) bool {
	mcells := x.GetMergeCells(sheet)
	for k, v := range mcells {
		if cell == k {
			return true
		}
		if inRange(v.Range, cell) {
			return true
		}
	}
	return false
}

//WriteCells 向指定的sheet写入值
func (x *XlsxHelper) WriteCells(sheet string, cells map[string]string) error {
	for k, v := range cells {
		x.file.SetCellValue(sheet, k, v)
	}
	return nil
}

//GetMergeCells 获取合并的单元格
func (x *XlsxHelper) GetMergeCells(sheet string) (mergeCells map[string]MergeCell) {
	var ok bool
	if mergeCells, ok = x.sheetMCells[sheet]; ok {
		return
	}
	mcells, _ := x.file.GetMergeCells(sheet)
	mergeCells = make(map[string]MergeCell, len(mcells))
	var scell, ecell string
	var scol, srow, ecol, erow int
	for _, mc := range mcells {
		scell = mc.GetStartAxis()
		ecell = mc.GetEndAxis()
		scol, srow, _ = parseAxis(scell)
		ecol, erow, _ = parseAxis(ecell)
		mergeCells[scell] = MergeCell{
			Range:   mc[0],
			Value:   mc.GetCellValue(),
			Rowspan: erow - srow + 1,
			Colspan: ecol - scol + 1,
		}
	}
	x.sheetMCells[sheet] = mergeCells
	return
}

//GetCloumnWidths 获取单元格的宽度
func (x *XlsxHelper) GetCloumnWidths(sheet string, sCol, ecol string) (colWids map[int]float64, sum float64, err error) {
	var si, ei int
	si, err = excelize.ColumnNameToNumber(sCol)
	if err != nil {
		return
	}
	ei, err = excelize.ColumnNameToNumber(ecol)
	if err != nil {
		return
	}
	if si > ei {
		return
	}
	colWids = make(map[int]float64, ei+1)
	var alp string
	for i := si; i <= ei; i++ {
		alp, _ = excelize.ColumnNumberToName(i)
		colWids[i], err = x.file.GetColWidth(sheet, alp)
		if err != nil {
			return
		}
		colWids[i] = colWids[i] * 2.117 / 0.3527
		sum += colWids[i]
	}
	return
}

func parseRanges(ranges []string) (rgs []Range, err error) {
	if ranges == nil {
		return
	}
	rgs = make([]Range, len(ranges), len(ranges))
	var scol, ecol, srow, erow int
	for i, rg := range ranges {
		scol, ecol, srow, erow, err = parseRange(rg)
		if err != nil {
			return
		}
		rgs[i] = Range{
			SCol: scol,
			ECol: ecol,
			SRow: srow,
			ERow: erow,
		}
	}
	return
}

func parseRange(rangeExp string) (scol, ecol, srow, erow int, err error) {
	if rangeExp == "" {
		return
	}
	rs := strings.Split(rangeExp, ":")
	if len(rs) != 2 {
		err = fmt.Errorf("错误的范围表达式%s", rangeExp)
		return
	}
	scol, srow, err = parseAxis(rs[0])
	if err != nil {
		return
	}
	ecol, erow, err = parseAxis(rs[1])
	return
}

func parseAxis(axis string) (col, row int, err error) {
	axis = strings.ToUpper(axis)
	abs := []byte(axis)
	var abi int
	var rowStart int
	for i, ab := range abs {
		abi = int(ab)
		if rowStart == 0 {
			if i > 0 && abi > 48 && abi <= 57 {
				rowStart = i
				continue
			}
			if abi < 65 || abi > 90 {
				err = fmt.Errorf("非法的单元格表达式%s", axis)
				return
			}
		} else {
			if abi < 48 || abi > 57 {
				err = fmt.Errorf("非法的单元格表达式%s", axis)
				return
			}
		}
	}
	colStr := axis[0:rowStart]
	rowStr := axis[rowStart:]
	col, err = excelize.ColumnNameToNumber(colStr)
	if err != nil {
		return
	}
	row, err = strconv.Atoi(rowStr)
	if err != nil {
		err = fmt.Errorf("非法的单元格表达式%s", axis)
	}
	return
}
